package com.gintama;

import com.gintama.redis.redisson.RedissonUser;
import org.junit.jupiter.api.Test;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.concurrent.TimeUnit;

@SpringBootTest(classes = GintamaServiceApplication.class)
public class RedissonDemo {

    //注入RedissonClient
    @Autowired
    RedissonClient redissonClient;

    @Test
    public void test(){
        //创建一个User对象
        RedissonUser user = new RedissonUser(1, "test", "password");
        //获得一个RBucket实现类，参数是redis数据库中的key值
        RBucket<RedissonUser> bucket = redissonClient.getBucket("user:" + user.getId());
        //执行set语句，将user对象存入redis中
        bucket.set(user);
    }

    @Test
    public void get(){
        //获得一个RBucket实现类，参数是redis数据库中的key值
        RBucket<RedissonUser> bucket = redissonClient.getBucket("user:1" );
        RedissonUser user = bucket.get();
        System.out.println(user);
    }

    @Test
    public void delete(){
        //获得一个RBucket实现类，参数是redis数据库中的key值
        RBucket<RedissonUser> bucket = redissonClient.getBucket("user:1" );
        bucket.delete();
    }


    /**
     * 分布式集合案例
     * 当使用Redisson的分布式集合功能时，你可以在分布式环境中创建和操作各种类型的集合数据结构，如List、Set、Map等。这些集合数据结构会被存储在Redis中，并能够在不同的Java应用程序或服务之间共享和访问。下面我将分别给出List、Set的使用示例（Map同理）。
     */
    @Test
    public void list(){
        //在redis中创建一个key为testList的list
        RList<String> list = redissonClient.getList("testList");
        /*
        注意：只要执行了add操作，就已经在redis中存入该数据了，并不需要另外的其他操作
         */
        list.add("one");
        list.add("two");
        list.add("three");
    }

    @Test
    public void list1(){
        RList<String> list = redissonClient.getList("testList");
        System.out.println(list);
    }

    @Test
    public void set(){
        RSet<Integer> set = redissonClient.getSet("testSet");
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(1);//Set不允许重复元素，这个操作不会被执行

        System.out.println("redis中testSet的值是："+set);
    }


    /**
     * Redisson实现分布式锁
     * Redisson的优点就是实现分布式锁就像实现JVM锁一样，因为它继承了JUC的Lock接口
     */
    @Test
    public void lock(){
        //会在redis中添加一个Map数据类型，Map的key是myLock
        RLock lock = redissonClient.getLock("myLock");
        try {
            // 尝试加锁，等待时间为10秒，过期时间为30秒
            boolean isLocked = lock.tryLock(1, 3, TimeUnit.SECONDS);
            if (isLocked){
                // 成功获取到锁，执行业务逻辑
                System.out.println("获取锁成功，即将执行业务逻辑...");
                Thread.sleep(30);
            }else {
                // 获取锁失败，处理相应逻辑
                System.out.println("获取锁失败，处理相应逻辑...");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
            System.out.println("释放锁成功");
        }
    }

    /**
     * 缓存穿透
     */
    @Test
    public void cachePenetration(){
        String key = "nonExistentKey";
        RMap<String, String> map = redissonClient.getMap("testMap");
        String value = map.get(key);
        if(value == null){
            // 模拟数据库查询
            String dbValue = queryFromDatabase(key);
            if (dbValue != null){
                // 如果数据库中也不存在，设置一个空值到缓存中，并设置较短的过期时间
                map.fastPut(key,"null");
            }else {
                map.put(key, dbValue);
            }
        }
    }
    private String queryFromDatabase(String key) {
        // 模拟数据库查询
        return "null";
    }

    /**
     * 缓存穿透 - 使用布隆过滤器解决方案
     */
    @Test
    public void cachePenetrationWithBloomFilter() {
        RBloomFilter<String> bloomFilter = redissonClient.getBloomFilter("myBloomFilter");
        // 初始化布隆过滤器，预计插入元素数量和期望的误判率
        bloomFilter.tryInit(1000000, 0.01);

        // 假设这些是存在的数据，将其添加到布隆过滤器中
        bloomFilter.add("key1");
        bloomFilter.add("key2");

        String key = "nonExistentKey";
        if (!bloomFilter.contains(key)) {
            System.out.println("数据不存在，避免查询数据库");
            return;
        }

        RMap<String, String> map = redissonClient.getMap("testMap");
        String value = map.get(key);
        if (value == null) {
            // 模拟从数据库查询数据
            String dbValue = queryFromDatabase(key);
            if (dbValue != null) {
                map.put(key, dbValue);
            }
        }
        System.out.println("Value from cache: " + map.get(key));
    }

}
